package dxbridge.model.impl;

import java.util.LinkedList;
import java.util.List;


import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import dxbridge.model.IDataSet;
import dxbridge.model.IRecord;
import dxbridge.model.ITable;

/**
 * <pre>
 * A DataSet represent a memory model of an Allora format xml data file.
 * Because a data file may contains multi-table, a DataSet also contains a list of {@link Table}.
 * </pre>
 * 
 * Typically , a DataSet should be generate from
 * {@link AlloraMapping#getDataSet()}, this will return a dataSet with only
 * table structures, then
 * {@link DataXMLParser#parseAlloraDoc(Document, DataSet)} can be used to fill
 * {@link Record} in this DataSet.
 * 
 */
public class DataSet implements IDataSet {

    /**
     * Create a DataSet with empty tables, and empty name.
     */
    public DataSet() {
        this.tables = new LinkedList<ITable>();
        dataSetName = "";
    }

    /**
     * Create a new DataSet instance with same structure and <b>without</b> data
     * records.
     * 
     * @param ds
     *            The origin DataSet to be be copy.
     */
    public DataSet(DataSet ds) {
        this.tables = new LinkedList<ITable>();
        for (int i = 0; i < ds.tables.size(); i++) {
            this.tables.add(new Table(ds.tables.get(i)));
        }
        this.dataSetName = ds.getDataSetName();
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#containsSameTables(model.impl.IDataSet)
     */
    public boolean containsSameTables(IDataSet ds) {

        for (int i = 0; i < tables.size(); i++) {
            if (ds.getTable(tables.get(i).getTableName()) == null) {
                return false;
            }
        }
        for (int i = 0; i < ds.getTables().size(); i++) {
            if (this.getTable(ds.getTables().get(i).getTableName()) == null) {
                return false;
            }
        }
        return true;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#getNumOfRecords()
     */
    public int getNumOfRecords() {
        int r = 0;
        for (ITable t : this.tables) {
            r += t.getRecords().size();
        }
        return r;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#getTable(java.lang.String)
     */
    public ITable getTable(String tableName) {
        if (tableName != null) {
            for (ITable t : tables) {
                if (t.getTableName().equals(tableName)) {
                    return t;
                }
            }
        } else {
            // should return null;
        }
        return null;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#getTables()
     */
    public List<ITable> getTables() {
        return tables;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#setTables(java.util.List)
     */
    public void setTables(List<ITable> tables) {
        this.tables = tables;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#addTable(model.impl.Table)
     */
    public void addTable(ITable table) {
        tables.add(table);
    }

    /**
     * Get all table's name contained in this DataSet. Sequence is not
     * guaranteed.
     * 
     * @return List of String contains the names of tables.
     */
    List<String> getTableNames() {
        List<String> nameList = new LinkedList<String>();
        for (ITable t : tables) {
            nameList.add(t.getTableName());
        }
        return nameList;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#getFlatDocument()
     */
    public Document getFlatDocument() {
        Document doc = null;
        Element root = DocumentHelper.createElement("xmlroot");
        for (int i = 0; i < tables.size(); i++) {
            List<IRecord> records = tables.get(i).getRecords();
            for (int j = 0; j < records.size(); j++) {
                root.add(records.get(j).toXMLElement());
            }
        }
        if (root.nodeCount() != 0) {
            doc = DocumentHelper.createDocument();
            doc.add(root);
        }

        return doc;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#printTest()
     */
    public void printTest() {
        System.out.println(String.format("DataSet contains %d tables:", tables
                .size()));

        /* test for tables in this data set */
        for (int i = 0; i < tables.size(); i++) {
            System.out.println(String.format("%d. %s", i, tables.get(i)
                    .getTableName()));
            tables.get(i).printTest();
        }

    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#getDataSetName()
     */
    public String getDataSetName() {
        return dataSetName;
    }

    /* (non-Javadoc)
     * @see model.impl.IDataSet#setDataSetName(java.lang.String)
     */
    public void setDataSetName(String dataSetName) {
        this.dataSetName = dataSetName;
    }

    /**
     * A List contains tables containing in this dataSet.
     */
    private List<ITable> tables;

    /**
     * The name of this dataSet, should be the file name of mapping file without
     * "mapping-" prefix.
     */
    private String dataSetName;
}
